package com.xiaomo.gitee.datamanager.controller;

import com.xiaomo.gitee.datamanager.common.exception.UsernameExistedException;
import com.xiaomo.gitee.datamanager.common.result.Code;
import com.xiaomo.gitee.datamanager.common.result.Result;
import com.xiaomo.gitee.datamanager.dto.security.TokenDTO;
import com.xiaomo.gitee.datamanager.dto.security.UserDTO;
import com.xiaomo.gitee.datamanager.security.service.impl.UserServiceImpl;
import com.xiaomo.gitee.datamanager.util.AuthorizeUtils;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;

@RestController
@Tag(name = "账户安全相关",description = "注册登录，安全检测等")
@RequiredArgsConstructor
public class AuthenticationController {

    private final UserServiceImpl userService;

    @PostMapping("/register")
    @Operation(
            summary = "注册账户",
            description = "用户注册新账户",
            parameters = {
                    @Parameter(
                            name = "user",
                            description = "用户信息模型",
                            required = true,
                            schema = @Schema(
                                    implementation = UserDTO.class
                            )
                    )
            },
            responses = {
                    @ApiResponse(
                            responseCode = Code.SUCCESS,
                            description = "注册成功",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = Code.USERNAME_EXISTED,
                            description = "用户名已存在",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    )
            }
    )
    public Result<?> register(@RequestBody UserDTO user) throws UsernameExistedException {
        userService.register(user);
        return Result.ok("注册成功",null);
    }

    /*@GetMapping({"/error/{code}","/result/{code}"})
    public String result(@PathVariable String code, Model model, HttpServletRequest request) {
        int result;
        try {
            result = Integer.parseInt(code);
        } catch (NumberFormatException e) {
            model.addAttribute("msg", "错误: 请求错误");
            return "/resultPage";
        }
        String msg = Code.getInfo(result);
        String uri = request.getRequestURI();
        if (uri.startsWith("/error/")) {
            model.addAttribute("msg", "错误: " + msg);
        } else if (uri.startsWith("/result/")) {
            model.addAttribute("msg", msg);
        }
        return "/resultPage";
    }*/

    @GetMapping("/login")
    @Hidden
    public ModelAndView loginPage(HttpServletResponse response) throws IOException {
        if (hasLogin()) {
            response.sendRedirect("/doc.html");
            return null;
        }
        return new ModelAndView("/login");
    }

    @DeleteMapping("/user")
    @PreAuthorize("hasAuthority('user_delete')")
    @Operation(
            summary = "删除用户",
            description = "管理员删除已存在的用户",
            parameters = {
                    @Parameter(
                            name = "username",
                            description = "用户名",
                            required = true
                    )
            },
            responses = {
                    @ApiResponse(
                            responseCode = Code.SUCCESS,
                            description = "成功",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = Code.USERNAME_NOTFOUND,
                            description = "用户名未找到",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    )
            }
    )
    public Result<?> deleteUser(@RequestParam("username")String username) throws UsernameNotFoundException {
        return userService.deleteUser(username) ? Result.ok() : Result.fail(Integer.parseInt(Code.USERNAME_NOTFOUND),Code.getInfo(Code.USERNAME_NOTFOUND));
    }

    @PostMapping("/login-api")
    @Operation(
            summary = "登录api",
            description = "用户进行登录的接口,返回登录认证token",
            parameters = {
                    @Parameter(
                            name = "user",
                            description = "用户数据模型",
                            schema = @Schema(
                                    implementation = UserDTO.class
                            )
                    )
            },
            responses = {
                    @ApiResponse(
                            responseCode = Code.SUCCESS,
                            description = "登录成功",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = TokenDTO.class
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = Code.LOGIN_FAILED_INCORRECT_PASSWORD,
                            description = "账号或密码错误",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = Code.UNKNOWN_ERROR,
                            description = "登录发生未知错误",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = Code.USER_HAS_LOGIN,
                            description = "用户已经登录了(带请求头访问)",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    )
            }
    )
    public Result<?> loginApi(@RequestBody UserDTO user) throws Exception {
        return Result.ok("登录成功",userService.login(user));
    }

    @GetMapping("/logout")
    @Hidden
    public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) {
        if (!hasLogin()) {
            return new ModelAndView("login/login");
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        new SecurityContextLogoutHandler()
                .logout(request,response,authentication);
        authentication.setAuthenticated(false);
        return new ModelAndView("/login");

    }

    @GetMapping("/perms")
    @Operation(
            summary = "获取用户权限列表",
            responses = {
                    @ApiResponse(
                            responseCode = Code.SUCCESS,
                            description = "获取成功",
                            content = @Content(
                                    mediaType = "application/json",
                                    array = @ArraySchema(
                                            schema = @Schema(
                                                    implementation = String.class
                                            )
                                    )
                            )
                    ),
                    @ApiResponse(
                            responseCode = Code.ACCESS_DENIED,
                            description = "用户未登录",
                            content = @Content(
                                    mediaType = "application/json",
                                    schema = @Schema(
                                            implementation = Result.class
                                    )
                            )
                    )
            }
    )
    public Result<?> getUserPermissions() {
        if (!SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
            return Result.fail(Integer.parseInt(Code.ACCESS_DENIED),"用户未登录");
        }
        return Result.ok(AuthorizeUtils.getPermissions());
    }

    private boolean hasLogin() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication authentication = securityContext.getAuthentication();
        return (authentication != null && authentication.isAuthenticated() && !(authentication instanceof AnonymousAuthenticationToken));
    }


}
